package games;

import gameUtils.Coordinate;
import gameUtils.GameMath;
import gameUtils.IOManager;
import games.gameObjects.Path;
import games.gameObjects.TDObject;
import games.gameObjects.invaders.Bug;
import games.gameObjects.invaders.Dragon;
import games.gameObjects.invaders.Invader;
import games.gameObjects.towers.Tower;

import java.awt.Color;
import java.awt.Point;
import java.awt.geom.Line2D;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;

import javax.swing.JOptionPane;

import pt.iul.poo.image.properties.GameWindowInterface;
import pt.iul.poo.shapes.SimpleShape;

public class GUI {

	private GameWindowInterface window;
	private String playername;
	private Queue<Map> mapsQueue = new LinkedList<Map>();
	private IOManager ioManager;
	private Map actualMap;
	private Market market;
	private int points = 100;
	private int timeCounter;
	private LinkedList<SimpleShape> simpleShapesList = new LinkedList<SimpleShape>();
	private boolean gameOver = false;

	public GUI(final GameWindowInterface window) {
		super();

		this.window = window;
		ioManager = new IOManager();
		ioManager.loadMapFiles();
		mapsQueue.addAll(ioManager.getMapsList());

		market = new Market();

		askPlayerName();
		showHowToPlay();
		window.start();
	}

	private void init() {
		fakeInit();
	}

	private void fakeInit() {
		market.clear();
		window.getDisplayer().clearImages();

		for (int i = 0; i < actualMap.getObjectsMapList().size(); i++) {
			window.getDisplayer().add(actualMap.getObjectsMapList().get(i).getImage());
		}
	}

	public void run() {

		actualMap = mapsQueue.peek();
		timeCounter = 0;

		init();


		while (!actualMap.mobsAllCleared() && points > 0) {
			moveCreeps();
			towerShots();
			// ...
			List<Integer> keyEvents = window.getKeyEvents();
			List<Point> mouseEvents = window.getMouseEvents();

			if(keyEvents.size() > 0)
				market.setKey(keyEvents.get(0));

			if(mouseEvents.size() > 0){
				market.setMouse(mouseEvents.get(0));

				if(market.getKey() != null){
					if(actualMap.getTowerAt(market.getMouse()) == null && actualMap.isGrass(market.getMouse())){
						TDObject tower = market.buyObject();
						window.getDisplayer().add(tower.getImage());
						actualMap.add(tower);
						market.clear();
					}

				} else if(market.getKey() == null){
					Tower sellingTower = actualMap.getTowerAt(market.getMouse());
					if(sellingTower != null){
						market.sellTower(sellingTower);
						window.getDisplayer().remove(sellingTower.getImage());
						actualMap.remove(sellingTower);
						market.clear();
					}
				}
				timeCounter++;
			}
			// ...

			window.setMessage("pts=" + points + " " + market.toString() + " diff tws=" + market.getDifferentTypes());


			createCreeps();

			window.getDisplayer().refresh();
			try {
				Thread.sleep(400);
			} catch (InterruptedException e) {
				//TODO
				e.printStackTrace();
			}

			removeCreeps();
			timeCounter++;



		}


		if(actualMap.mobsAllCleared()){
			mapsQueue.poll();

			if(mapsQueue.size() > 0){
				run();
			}
		}


		if(!gameOver){
			System.out.println("ESTOU AQUI");
			gameOver = true;
			window.getDisplayer().clearImages();
			window.end();
			showRanking();
		}
	}

	private void createCreeps() {
		if(timeCounter > 6){

			Random random = new Random();
			if(random.nextInt(4) == 0){

				int invadersToBeCreated = actualMap.getInvadersToBeCreated();
				Path firstPath = actualMap.getPathList().getFirst();

				if(actualMap.getInvaderAt(firstPath.getCoordinate()) == null){

					if(invadersToBeCreated > 1) {
						Bug bug = new Bug(new Coordinate(firstPath.getCoordinate().getAbcissa(), firstPath.getCoordinate().getOrdinate()));
						window.getDisplayer().add(bug.getImage());
						actualMap.add(bug);
						actualMap.decrementInvadersToBeCreated();

					} else if(invadersToBeCreated == 1){
						Dragon dragon = new Dragon(new Coordinate(firstPath.getCoordinate().getAbcissa(), firstPath.getCoordinate().getOrdinate()));
						window.getDisplayer().add(dragon.getImage());
						actualMap.add(dragon);
						actualMap.decrementInvadersToBeCreated();
					}
				}
			}
		}
	}

	private void towerShots() {
		LinkedList<Tower> towerList = actualMap.getTowerList();
		LinkedList<Invader> invaderList = actualMap.getInvaderList();


		if(!simpleShapesList.isEmpty()){
			for (int i = 0; i < simpleShapesList.size(); i++) {
				window.getDisplayer().remove(simpleShapesList.get(i));
			}
			simpleShapesList = new LinkedList<SimpleShape>();
		}


		for (int i = 0; i < towerList.size(); i++) {
			for (int j = 0; j < invaderList.size(); j++) {
				if(GameMath.distanceBetween(towerList.get(i).getCoordinate(), invaderList.get(j).getCoordinate()) < towerList.get(i).getRange()){
					invaderList.get(j).setHealthPoints(towerList.get(i).getDamage());
					SimpleShape s = new SimpleShape(new Line2D.Double(
							towerList.get(i).getImage().getPosition().getX() + towerList.get(i).getImage().getDimension().width / 2, 
							towerList.get(i).getImage().getPosition().getY() + towerList.get(i).getImage().getDimension().height / 2, 
							invaderList.get(j).getImage().getPosition().getX() + invaderList.get(j).getImage().getDimension().width / 2, 
							invaderList.get(j).getImage().getPosition().getY() + invaderList.get(j).getImage().getDimension().height / 2),
							Color.GREEN, 50);

					simpleShapesList.add(s);
					window.getDisplayer().add(s);
				}
			}
		}
	}

	private void moveCreeps() {
		LinkedList<Invader> invaderList = actualMap.getInvaderList();
		for (int i = 0; i < invaderList.size(); i++) {
			Coordinate nextCoordinate = actualMap.getNextPathCoordinate(invaderList.get(i).getCoordinate());
			if(nextCoordinate != null && actualMap.getInvaderAt(nextCoordinate) == null){
				invaderList.get(i).setCoordinate(nextCoordinate);
			}
		}
	}

	private void removeCreeps() {
		LinkedList<Invader> invaderList = actualMap.getInvaderList();
		Path lastPath = actualMap.getPathList().getLast();
		LinkedList<Invader> removingInvadersMapList = new LinkedList<Invader>();

		for (int i = 0; i < invaderList.size(); i++) {

			if(invaderList.get(i).getHealthpoints() <= 0){
				market.addBudget(invaderList.get(i).getValue());
				window.getDisplayer().remove(invaderList.get(i).getImage());
				removingInvadersMapList.add(invaderList.get(i));

			} else if(invaderList.get(i).getCoordinate().equals(lastPath.getCoordinate())){
				points -= 10;
				window.getDisplayer().remove(invaderList.get(i).getImage());
				removingInvadersMapList.add(invaderList.get(i));
			}
		}

		LinkedList<TDObject> l = new LinkedList<TDObject>();
		l.addAll(removingInvadersMapList);
		actualMap.removeAll(l);
	}

	private void showRanking() {
		RankingEntry entry = new RankingEntry(playername, actualMap.getId(), actualMap.getDestroyedInvaders(), market.getBudget());

		LinkedList<RankingEntry> rankingEntries = IOManager.loadAndSaveRanking(entry);

		String text = "                                RANKING                                    \n";

		for (RankingEntry e : rankingEntries) {
			int num = rankingEntries.indexOf(e);
			text += (num + 1) + " " + getText(num) + " Place:\n";
			text += e.toString() + "\n";
		}

		JOptionPane.showMessageDialog(null, text);
	}

	private String getText(int num){
		if(num == 0) return "st";
		if(num == 1) return "nd";
		if(num == 2) return "rd";

		return "th";
	}




	private void showHowToPlay() {
		String text = "********* Tower Defense *********" + "\n" +
		"									" +		
		" Invaders want you dead.. dont let \n them " +
		" reach the other side of the valley.. or \n the human kind" +
		" will be extinct !!" + "\n" +
		" Put towers on the map and save \n everyone! \n\n" + 
		" How to Play: \n"	+
		" Select number : 1 to 9 to select \n different type of tower " + "\n \n" +
		" diff towers - is the number of \n different towers available " + "\n" +
		" budget - allows you to buy towers " + "\n" +
		" points - if it reaches 0 you loose ";

		JOptionPane.showMessageDialog(null, text);
	}

	private void askPlayerName() {
		String name = JOptionPane.showInputDialog(null, "Player name:");
		if(name == null || name.isEmpty())
			askPlayerName();
		else
			playername = name;
	}

}
